package com.mazaiting.rabbitmq.service.impl;

import com.alibaba.fastjson.JSON;
import com.mazaiting.common.core.domain.result.ResultCode;
import com.mazaiting.common.core.ex.exceptions.BaseException;
import com.mazaiting.common.core.ex.exceptions.BusinessException;
import com.mazaiting.common.core.ex.exceptions.EmptyObjectException;
import com.mazaiting.rabbitmq.constant.MqConstant;
import com.mazaiting.rabbitmq.domain.info.MessageInfo;
import com.mazaiting.rabbitmq.service.IMqMessageService;
import com.mazaiting.rabbitmq.service.IMqService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageBuilder;
import org.springframework.amqp.core.MessageBuilderSupport;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.nio.charset.StandardCharsets;
import java.util.Objects;

/**
 * 发送消息
 *
 * @author mazaiting
 * @create_time 2022/3/28 15:48
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class MqServiceImpl implements IMqService {

    private final RabbitTemplate rabbitTemplate;

    private final IMqMessageService mqMessageService;

    @Override
    public <T> void sendMessage(MessageInfo<T> messageInfo) throws BaseException {
        // 交换机
        String exchange = messageInfo.getExchange();
        if (!StringUtils.hasLength(exchange)) {
            throw new BusinessException(ResultCode.MQ_EXCHANGE_EMPTY);
        }
        // 路由 key
        String routingKey = messageInfo.getRoutingKey();
        if (!StringUtils.hasLength(routingKey)) {
            throw new BusinessException(ResultCode.MQ_ROUTING_KEY_EMPTY);
        }
        // 获取数据
        T data = messageInfo.getData();
        // 判断当前数据为空
        if (Objects.isNull(data)) {
            throw new EmptyObjectException(ResultCode.MQ_DATA_EMPTY);
        }
        // 数据转换
        String json = data instanceof String ? (String) data : JSON.toJSONString(data);
        // 超长报错
        if (json.length() > MqConstant.MESSAGE_MAX_LENGTH) {
            throw new BusinessException(ResultCode.MQ_MESSAGE_OVER_MAX_LENGTH);
        }
        // 保存消息实体, 并返回消息 ID
        String messageId = mqMessageService.save(messageInfo);
        sendMessage(exchange, routingKey, messageId, json, messageInfo.getExpiration());
    }

    /**
     * 发送消息
     *
     * @param exchange   交换机
     * @param routingKey 路由key
     * @param messageId  消息 ID
     * @param data       数据
     * @param expiration 过期时间
     */
    public void sendMessage(String exchange, String routingKey, String messageId, String data, int expiration) {
        // 构造消息
        MessageBuilderSupport<Message> messageBuilderSupport = MessageBuilder.withBody(data.getBytes(StandardCharsets.UTF_8)).setMessageId(messageId);
        // 大于 0
        if (expiration > MqConstant.DEFAULT_EXPIRATION_0) {
            // 设置过期时间
            messageBuilderSupport.setExpiration(String.valueOf(expiration));
        }
        // 创建消息
        Message message = messageBuilderSupport.build();
        // 发送消息
        sendMessage(exchange, routingKey, messageId, message);
    }


    /**
     * 发送消息
     *
     * @param exchange   交换机
     * @param routingKey 路由key
     * @param messageId  消息 ID
     * @param message    消息
     */
    public void sendMessage(String exchange, String routingKey, String messageId, Message message) {
        log.info("发送消息, 交换机: {}, 路由 key: {}, 消息 ID: {}", exchange, routingKey, messageId);
        // 发送消息
        rabbitTemplate.convertAndSend(exchange, routingKey, message, new CorrelationData(messageId));
    }

}
